Skip to main content

作业

IconSwitch组件的开发与测试

IconSwitch组件

使用了ant-design-vue中的a-tooltip和a-button组件。

<template>
 <div class="icon-switch">
   <a-tooltip :placement="placement" :title="title">
     <a-button :type="type" :shape="shape" @click="onChange">
       <slot></slot>
     </a-button>
   </a-tooltip>
 </div>
</template>

<script lang="ts">
import { defineComponent, computed } from 'vue';

export default defineComponent({
 name: 'IconSwitch',
 props: {
   value: {
     type: Boolean,
     default: false
  },
   placement: {
     type: String,
     default: 'top'
  },
   title: {
     type: String,
     default: 'title'
  },
   shape: {
     type: String,
     default: 'circle'
  }
},
 emits: ['change'],
 setup(props, context) {
   const type = computed(() => {
     return props.value ? 'primary' : '';
  });
   const onChange = () => {
     context.emit('change', !props.value);
  };
   return {
     type,
     onChange
  };
}
});
</script>

单元测试

import { mount, VueWrapper } from '@vue/test-utils';
import IconSwitch from '@/components/IconSwitch.vue';

const mockComponent = {
 template: '<div><slot>B</slot></div>'
};
let wrapper: VueWrapper<any>;
const title = '我是鼠标悬浮提示';
describe('IconSwitch.vue', () => {
 beforeAll(() => {
   wrapper = mount(IconSwitch, {
       props: {
         value: true,
         title
      },
       global: {
         components: {
           'a-button': mockComponent,
           'a-tooltip': mockComponent
        }
      }
    }
  );
});
 it('测试title', () => {
   const tooltip = wrapper.findAll('.icon-switch>div')[0];
   // 判断传入的title
   expect(tooltip.attributes('title')).toBe(title);
});
 it('测试title位置', async () => {
   const tooltip = wrapper.findAll('.icon-switch>div')[0];
   expect(tooltip.attributes('placement')).toBe('top');
   await wrapper.setProps({
     placement: 'topLeft'
  });
   // 判断传入的placement是否正确
   expect(tooltip.attributes('placement')).toBe('topLeft');
});

 it('测试value值', async () => {
   // 判断传入的value值
   expect(wrapper.props('value')).toBeTruthy();
});
 it('测试value值 - 2', async () => {
   await wrapper.setProps({
     value: false
  });
   // 判断传入的value值
   expect(wrapper.props('value')).toBeFalsy();
});

 it('测试点击事件', async () => {
   const item = wrapper.get('div[type=primary]');
   // 触发点击事件
   await item.trigger('click');
   const events = wrapper.emitted('change');
   // 传入属性为 value === true,取反则为false
   expect(events[0]).toEqual([false]);
});
 afterEach(() => {
   // 测试value值 - 2 会更改props,如果不还原会导致测试点击事件失败
   wrapper.setProps({
     value: true
  });
});
});

集成到编辑器

步骤一

由于使用了图标,需要安装@ant-design/icons-vue,命令如下

cnpm install --save @ant-design/icons-vue

步骤二

在PropsTable组件中引入要使用的IconSwitch和字体组件

import IconSwitch from '@/components/IconSwitch.vue';
import BoldOutlined from '@ant-design/icons-vue/BoldOutlined';
import ItalicOutlined from '@ant-design/icons-vue/ItalicOutlined';
import UnderlineOutlined from '@ant-design/icons-vue/UnderlineOutlined';

步骤三

组件外层循环增加一个新的类名,命名规则为“组件名-item”,如icon-switch-item

步骤四

增加如下css样式

.icon-switch-item {
 display: inline-block;
 margin-right: 10px;
}

步骤五

设置第一个icon-switch距离左边的位置

    onMounted(() => {
     const firstElement = document.getElementsByClassName('icon-switch-item')[0] as HTMLElement;
     firstElement.style.paddingLeft = '28%';
  });

步骤六

编写css属性与组件的映射关系

  fontWeight: {
   component: 'icon-switch',
   subComponent: 'BoldOutlined',
   text: '',
   extraProps: {
     title: '常规/加粗'
  },
   initalTransform(value: string) {
     return value === 'bold';
  },
   afterTransform(value: boolean) {
     return value ? 'bold' : 'normal';
  },
   options: [{value: '', text: ''}]
},
 fontStyle: {
   component: 'icon-switch',
   subComponent: 'ItalicOutlined',
   text: '',
   extraProps: {
     title: '常规/斜体'
  },
   initalTransform(value: string) {
     return value === 'italic';
  },
   afterTransform(value: boolean) {
     return value ? 'italic' : 'normal';
  },
   options: [{value: '', text: ''}]
},
 textDecoration: {
   component: 'icon-switch',
   subComponent: 'UnderlineOutlined',
   text: '',
   extraProps: {
     title: '常规/下划线'
  },
   initalTransform(value: string) {
     return value === 'underline';
  },
   afterTransform(value: boolean) {
     return value ? 'underline' : 'none';
  },
   options: [{value: '', text: ''}]
}